/**  
 * All rights Reserved, Designed By <a href="www.itttq.com" target="_blank">www.itttq.com</a>
 * @date:   2018年1月20日 下午12:06:13
 * @Copyright: 2018 <a href="www.itttq.com" target="_blank">www.itttq.com</a> Inc. All rights reserved. 
 */  
package com.itttq.gshop.h5.controller.pay;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.github.wxpay.sdk.WXPayConstants.SignType;
import com.itttq.gshop.domain.po.OrderInfoPo;
import com.itttq.gshop.domain.po.UserInfoPo;
import com.itttq.gshop.domain.to.ResultTo;
import com.itttq.gshop.generic.connector.IPayApplyConnector;
import com.itttq.gshop.generic.connector.IUserInfoConnector;
import com.itttq.gshop.generic.controller.GenericController;
import com.itttq.gshop.generic.util.Constants;
import com.itttq.gshop.generic.util.Constants.PayMethod;
import com.itttq.gshop.generic.util.Constants.PayStatus;
import com.itttq.gshop.h5.cmpt.GenericGrap;
import com.itttq.gshop.h5.controller.IndexController;
import com.itttq.gshop.h5.controller.order.OrderController;
import com.itttq.gshop.h5.controller.user.UserController;

/**   
 * 针对微信登录的访问地址，业务逻辑处理和其他一样，就是多了登录授权。
 * 规则：带有.html结尾的则是微信回调地址，即可以通过微信code获取用户信息的地址；
 * 不带.html结尾的则是调用微信授权地址
 * @ClassName:  IndexController
 * @author: 迷蝶
 * @date:   2018年1月20日 下午12:06:13 
 *     
 * @Copyright: 2018 <a href="www.itttq.com" target="_blank">www.itttq.com</a> Inc. All rights reserved. 
 */
@RestController
@RequestMapping("wx")
public class WeixinController extends GenericController {
	private static final long serialVersionUID = -6485190841311449L;
	private static Logger LOG = LoggerFactory.getLogger(WeixinController.class);
	@Autowired
	private IUserInfoConnector userConnector;
	@Autowired
	private IndexController indexController;
	@Autowired
	private OrderController orderController;
	@Autowired
	private UserController userController;
	@Autowired
	private IPayApplyConnector payApplyConnector;
	// 微信授权后获取用户信息地址，后面不带？号
	@Value("${wx.mp.auth.userUrl}")
	private String userUrl;
	// 微信授权地址，后面不带？号
	@Value("${wx.mp.auth.authUrl}")
	private String authUrl;
	// 微信使用code换区accessToken地址，后面不带？号
	@Value("${wx.mp.auth.accessTokenUrl}")
	private String accessTokenUrl;
	// 授权后重定向地址：首页
	@Value("${wx.mp.auth.redirect.indexUrl}")
	private String indexUrl;
	// 授权后重定向地址：订单页
	@Value("${wx.mp.auth.redirect.orderUrl}")
	private String orderUrl;
	// 授权后重定向地址：订单页
	@Value("${wx.mp.auth.redirect.mineUrl}")
	private String mineUrl;
	// 授权方式：snsapi_base或snsapi_userinfo
	@Value("${wx.mp.auth.scope}")
	private String scope;
	// STATe
	@Value("${wx.mp.auth.state}")
	private String state;
	// connectRedirect: 1
	@Value("${wx.mp.auth.connectRedirect}")
	private String connectRedirect;
	// responseType: code
	@Value("${wx.mp.auth.responseType}")
	private String responseType;
	// 链接后缀： #wechat_redirect
	@Value("${wx.mp.auth.postfix}")
	private String postfix;
	// 微信公众号appid
	@Value("${wx.mp.appid}")
	private String appid;
	// 微信公众号key，商户秘钥
	@Value("${wx.mp.secret}")
	private String secret;
	// 微信公众号key，商户秘钥
	@Value("${wx.mp.key}")
	private String key;
	/**
	 * 获取跳转授权的微信地址
	// https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx556d23b1815908d4&
	// redirect_uri=http://h5.wine22.com&response_type=code&scope=snsapi_base&state=STATE&connect_redirect=1#wechat_redirect
	 * @return
	 * @Author 迷蝶
	 * @return String
	 */
	private String getWxRedirectUrl(String url) {
		return authUrl + "?appid=" + appid + "&redirect_uri=" + url + "&response_type=" + responseType 
				+ "&scope=" + scope + "&state=" + state + "&connect_redirect=" + connectRedirect + "#" + postfix;
	}
	/**
	 * 微信授权用户登录处理，回调url如下：
	 * http://h5.wine22.com/?code=061mLukB1V6m9e0XPyjB1fFakB1mLuko&state=STATE
	 * 
	 * 获取access-token地址如下：
	 * https://api.weixin.qq.com/sns/oauth2/access_token?appid=appid&secret=secret&code=code&grant_type=authorization_code
	 * 响应结果格式：
	 * {"access_token":"token",
	 * "expires_in":7200,
	 * "refresh_token":"token",
	 * "openid":"openid",
	 * "scope":"snsapi_userinfo"}
	 * 
	 * 根据openid获取用户信息：
	 * https://api.weixin.qq.com/sns/userinfo?access_token=token&lang=zh_CN
	{"openid":"openid","nickname":"迷蝶","sex":1,"language":"zh_CN","city":"","province":"","country":"希腊",
	"headimgurl":"http:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/cn4EqgJGzt7G2Zka01IPKypPhMfz26qichlzTOq1JcuvyINcnykRBnpPXyjCNLOnRTuHKN9ohGgJYibXSmqolYkw\/132",
	"privilege":[]}
	 * @param code
	 * @return
	 * @Author 迷蝶
	 * @return String
	 */
	private UserInfoPo wxUserLogin(HttpServletRequest request, String code) {
		LOG.info("微信登录：code =  {}", code);
		// 使用code换取access-token
		UserInfoPo user = null;
		try {
			String url = accessTokenUrl + "?appid=" + appid + "&secret=" + secret 
					+ "&code=" + code + "&grant_type=authorization_code";
			LOG.info("微信登录：根据用户code获取access_token : url = {}", url);
			String rs = GenericGrap.getJsonContent(url);
			LOG.info("微信登录：获取access_token结果：{}",  rs);
			if(StringUtils.isNotBlank(rs)) {
				JSONObject  tokenJson = JSON.parseObject(rs);
				// 查找数据库是否有对应openId用户，有则直接登录，没有则继续获取
				String openid = tokenJson.getString("openid");
				if(StringUtils.isNotBlank(openid)) {
					user = userConnector.getUserByOpenid(openid);
					if(null != user) {
						this.setSession(request, Constants.SESSION_USER, user);
						return user;
					}
				}
				LOG.info("微信登录：用户不存在： openid= {}", openid);
				if(StringUtils.isNotBlank(tokenJson.getString("access_token"))) {
					// 获取accessToken后，根据token获取用户信息
					rs = GenericGrap.getJsonContent(userUrl + "?access_token=" + tokenJson.getString("access_token") 
							+ "&openid=" + openid + "&lang=zh_CN");
					LOG.info("微信登录：微信用户信息： {}", rs);
					if(StringUtils.isNotBlank(rs)) {
						JSONObject  userJson = JSON.parseObject(rs);
						// 获取用户基本信息，并保存在数据库
						user = new UserInfoPo();
						user.setOpenid(openid);
						user.setHead(userJson.getString("headimgurl"));
						user.setGender(userJson.getInteger("sex"));
						user.setUsername(userJson.getString("nickname"));
						user.setAddress(userJson.getString("province") + userJson.getString("city"));
						// TODO GXG 合并账户
						userConnector.saveUserInfo(user);
						LOG.info("wx user add success: user= {}", user);
						this.setSession(request, Constants.SESSION_USER, user);
					}
				}
			}
		} catch (IOException e) {
			LOG.error("微信登录：异常： {}", e);
		}
		return user;
	}
	
	/**
	 * 微信主页授权页面
	 * @return
	 */
	@RequestMapping(value={""})
	public ModelAndView index() {
		return new ModelAndView(new RedirectView(getWxRedirectUrl(indexUrl)));
	}
	
	/**
	 * 微信订单授权页面
	 * @return
	 */
	@RequestMapping("order")
	public ModelAndView order(String code, HttpServletRequest request) {
		return new ModelAndView(new RedirectView(getWxRedirectUrl(orderUrl)));
	}
	
	/**
	 * 微信个人中心授权页面
	 * @return
	 */
	@RequestMapping("mine")
	public ModelAndView mine(String code, HttpServletRequest request) {
		return new ModelAndView(new RedirectView(getWxRedirectUrl(mineUrl)));
	}

	/**
	 * 微信回调：主页展示页面
	 * @return
	 */
	@RequestMapping("index.html")
	public ModelAndView indexPage(HttpServletRequest request, String code) {
		wxUserLogin(request, code);
		return indexController.index();
	}
	
	/**
	 * 微信回调：订单展示页面
	 * @return
	 */
	@RequestMapping("order.html")
	public ModelAndView orderPage(HttpServletRequest request, String code) {
		wxUserLogin(request, code);
		return orderController.getOrders(new OrderInfoPo(), request);
	}
	
	/**
	 * 微信回调：个人中心展示页面
	 * @return
	 */
	@RequestMapping("mine.html")
	public ModelAndView minePage(HttpServletRequest request, String code) {
		wxUserLogin(request, code);
		return userController.index(request);
	}
	
	/**
	 * 微信回调：个人中心展示页面
	 * @return
	 */
	@RequestMapping("payTest.html")
	public ModelAndView payTest(HttpServletRequest request, String code) {
		return new ModelAndView("/order/pay-wx");
	}
	
	/**  
     * 微信订单异步回调接口  
     * @return  
     */  
    @RequestMapping(value = "notify.html", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")  
    @ResponseBody
    public void notify(HttpServletRequest request,HttpServletResponse response) {
        LOG.info("微信支付：结果回调开始");
    	Map<String, String> resultMap = new HashMap<String, String>();
        try {  
            request.setCharacterEncoding("UTF-8");    
            response.setCharacterEncoding("UTF-8");    
            response.setContentType("text/html;charset=UTF-8");    
            response.setHeader("Access-Control-Allow-Origin", "*");     
            InputStream in=request.getInputStream();    
            ByteArrayOutputStream out=new ByteArrayOutputStream();    
            byte[] buffer =new byte[1024];    
            int len=0;    
            while((len=in.read(buffer))!=-1){    
                out.write(buffer, 0, len);    
            }    
            out.close();    
            in.close();    
            String content=new String(out.toByteArray(),"utf-8");//xml数据
            LOG.info("微信支付：结果回调：{}", content);
            Map<String, String> rsMap = WXPayUtil.xmlToMap(content);
             // 回调签名校验
         // 校验签名
    		if(!WXPayUtil.isSignatureValid(rsMap, key, SignType.HMACSHA256)) {
    			LOG.info("pay apply wx signature valid result：false");
    			rt.setCode(ResultTo.PAY_ERR_SIGN);
    			return rt;
    		}
    		String returnCode = rsMap.get("return_code");
            if(returnCode.equalsIgnoreCase("FAIL")) {
                // 通信失败
                LOG.info("微信支付：结果回调失败");
            } else if(returnCode.equalsIgnoreCase("SUCCESS")){  
            	// 通信成功，判断业务结果是否成功
            	String resultCode = rsMap.get("result_code");
            	if(resultCode.equalsIgnoreCase("SUCCESS")) {
                    LOG.info("微信支付：支付成功");
            		// 支付成功：1、更新支付记录为成功；2、记录支付日志；3、更新订单状态
            		payApplyConnector.payResult(Integer.parseInt(rsMap.get("attach")), Integer.parseInt(rsMap.get("out_trade_no")), 
            				Integer.parseInt(rsMap.get("total_fee")), PayMethod.WXPAY, PayStatus.SUCCESS);
            	} else {
                    LOG.info("微信支付：支付失败");
            		// 支付失败：1、更新支付记录为失败；2、记录支付日志；
            		payApplyConnector.payResult(Integer.parseInt(rsMap.get("attach")), Integer.parseInt(rsMap.get("out_trade_no")), 
            				Integer.parseInt(rsMap.get("total_fee")), PayMethod.WXPAY, PayStatus.FAIL);
            	}
            }
            resultMap.put("return_code", "SUCCESS");
            resultMap.put("return_msg", "OK");
        } catch(Exception e) {
            resultMap.put("return_code", "FAIL");
            resultMap.put("return_msg", "结果回调异常");
            LOG.error("微信支付：结果回调异常：{}", e);
        }  
    }  
}
